﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using TinyROS.Messages;
using TinyROS.Exceptions;
using System.IO;

namespace TinyROS
{ 
    partial class SystemCore 
    {
        // 此部分负责各个命令的实现
        private List<(Assembly assembly, string ns)> LoadedAsm;
        private void LoadAssemblyHandler(string args)
        {
            try
            {
                var loadArg = args.Split(" ",SplitOption);
                var asmName = loadArg[0];
                var ns = loadArg[1];
                Assembly asm = null;
                try
                {
                    asm = Assembly.LoadFrom(asmName);
                }
                catch
                {

                }
                if (asm==null)
                {
                    throw new LoadAssemblyFailedException();
                }
                this.LoadedAsm.Add((asm, ns));
            }
            catch(IndexOutOfRangeException)
            {
                LogError("命令参数不正确", "Load");
                ConsoleWriteLineWithColor("用法： Load <程序集文件名> <命名空间名>", ConsoleColor.Yellow);
            }
            catch(LoadAssemblyFailedException)
            {
                LogError("未能成功加载程序集，请检查文件名", "Load");
            }
            catch(Exception e)
            {
                LogError("未能成功加载程序集", "Load");
                ConsoleWriteLineWithColor(e.StackTrace, ConsoleColor.White);
                
            }
        }
        private void ExecuteScriptHandler(string args)
        {
            try
            {
                var cmds = File.ReadAllLines(args);
                foreach (var cmd in cmds)
                {
                    if (cmd != "")
                    {
                        this.Execute(cmd);
                    }
                }
            }
            catch
            {

            }
        }
        private void HelpHandler()
        {
            try
            {
                var helpStr = @"TinyROS帮助
节点命令：
    node new <节点类型名> <节点名> [节点构造参数...]  
        新建节点
    node run <节点名>
        启动节点
    node stop <节点名>
        停止节点
    node info <节点名>
        查看节点信息
    node list
        查看节点列表
    node execute <节点名> <节点命令...>
        由节点执行命令
话题命令：
    topic new <话题类型名> <话题名>
        新建话题
    topic pub/publish <话题名> <消息构造参数>
        向话题发布一次消息
    topic delete <话题名>
        删除话题
    topic echo <话题名>
        侦听话题
    topic list
        查看话题列表
其他命令：
    load <程序集文件名> <命名空间名>
        加载指定程序集的指定命名空间
    execute <文件名>
        执行脚本
    ";

                ConsoleWriteLineWithColor(helpStr, ConsoleColor.White);
            }
            catch
            {

            }
            
        }
        private void NodeNewHandler(string args)
        {   
            try
            {
                var nodeNewArgs = args.Split(" ", 3, SplitOption);               
                string nodeTypeName = nodeNewArgs[0];
                Type nodeType = null;
                foreach(var asm in this.LoadedAsm)
                {
                    nodeType = asm.assembly.GetType(asm.ns + "." + nodeTypeName);
                    if(nodeType != null)
                    {
                        break;
                    }
                }
                if(nodeType == null)
                {
                    throw new NodeTypeNotFoundException(nodeTypeName);
                }
                var nodeName = nodeNewArgs[1];
                if(this.Nodes.ContainsKey(nodeName))
                {
                    throw new AlreadyExistException(nodeName);
                }
                string[] nodeConstructorArgs = null;
                if(nodeNewArgs.Length == 3)
                {
                    nodeConstructorArgs = nodeNewArgs[2].Split(" ", SplitOption);
                }               
                object nodeRawObj =  Activator.CreateInstance(nodeType, nodeConstructorArgs);
                var node = nodeRawObj as Node;
                if(node == null)
                {
                    throw new NodeInstanceCreateFailedException();
                }
                this.RegisterNode(nodeName, node, true);
                LogInfo("Sucessfully created new node", "Node new");
            }
            catch(IndexOutOfRangeException)
            {
                LogError("node new命令的参数不正确", "Invalid Command");
                ConsoleWriteLineWithColor("用法：node new <节点类型名称> <节点名称> [节点构造参数...]", ConsoleColor.Yellow);
            }
            catch(NodeTypeNotFoundException ntnfe)
            {
                var name = ntnfe.NodeTypeName;
                LogError($"未在已加载的程序集中找到指定名称的节点类型（{name}）", "Node Not Found");
            }
            catch(AlreadyExistException aee)
            {
                LogError($"节点的名称已经存在（{aee.ExistedName}）", "Name Already Exists");
            }
            catch(MissingMethodException)
            {
                LogError("节点构造失败，可能是参数与现有的任何构造函数不匹配", "Node Construct Failed");
            }
            catch(NodeInstanceCreateFailedException)
            {
                LogError("节点构造失败，可能是类型没有实现抽象类Node", "Node Create");
            } 
            catch(NodeInitFailedExcepiton)
            {
                LogError("节点初始化过程中出现异常，初始化失败", "Node Init");
            }
            catch(Exception e)
            {
                LogError("未预定义的节点初始化异常", "Node new");
                ConsoleWriteLineWithColor(e.StackTrace, ConsoleColor.Yellow);
            }
        }
        private void NodeDeleteHandler(string args)
        {
            var nodeName = args.Trim();
            try
            {                
                if(this.Nodes.ContainsKey(nodeName))
                {
                    var node = this.Nodes[nodeName];
                    node.Stop();
                    this.Nodes.Remove(nodeName);
                    if(node is IDisposable)
                    {
                        try
                        {
                            var d = node as IDisposable;
                            d.Dispose();
                        }
                        catch
                        {
                            throw new NodeDisposeExcepiton();
                        }
                    }
                    LogInfo("Successfully deleted node", "Node delete");
                }
                else
                {
                    throw new NodeNotExistExecption(nodeName);
                }
            }
            catch(NodeNotExistExecption)
            {
                LogError($"该名称的节点不存在({nodeName})", "Node Not Exist");
            }
            catch(NodeDisposeExcepiton)
            {
                LogWaring("已从系统中移除节点，但是非托管资源可能没有正常释放", "Node delete");
            }
            catch
            {
                LogError($"移除失败，可能是节点没有正常停止", "Node delete");
            }
        }
        private void NodeStartHandler(string args)
        {
            var nodeName = args.Trim();
            try
            {
                if(this.Nodes.ContainsKey(nodeName))
                {
                    var node = this.Nodes[nodeName];
                    node.Run();
                    LogInfo("Successfully started node", "Node start");
                }
                else
                {
                    throw new NodeNotExistExecption(nodeName);
                }
            }
            catch (NodeNotExistExecption)
            {
                LogError($"该名称的节点不存在({nodeName})", "Node Not Exist");
            }
            catch
            {
                LogError($"节点启动失败", "Node start");
            }
        }
        private void NodeStopHandler(string args)
        {
            var nodeName = args.Trim();
            try
            {
                if (this.Nodes.ContainsKey(nodeName))
                {
                    var node = this.Nodes[nodeName];
                    node.Stop();
                    LogInfo("Successfully stopped node", "Node start");
                }
                else
                {
                    throw new NodeNotExistExecption(nodeName);
                }
            }
            catch (NodeNotExistExecption)
            {
                LogError($"该名称的节点不存在({nodeName})", "Node Not Exist");
            }
            catch
            {
                LogError($"节点停止失败", "Node stop");
            }
        }
        private void NodeInfoHandler(string args)
        {
            var nodeName = args.Trim();
            try
            {
                if (this.Nodes.ContainsKey(nodeName))
                {
                    var node = this.Nodes[nodeName];
                    var nodeTypeName = node.GetType().FullName;
                    ConsoleWriteLineWithColor($"Node name: {nodeName}", ConsoleColor.White);
                    ConsoleWriteLineWithColor($"Node type: {nodeTypeName}", ConsoleColor.White);
                    ConsoleWriteLineWithColor($"IsRunning: {node.IsRunning}", ConsoleColor.White);
                    if(node.SubscribedTopicName.Count!=0)
                    {
                        ConsoleWriteLineWithColor("Subscribe from topics: ", ConsoleColor.White);
                    }
                    else
                    {
                        ConsoleWriteLineWithColor("Subscribe from: no topics: ", ConsoleColor.White);
                    }
                    foreach(var topicName in node.SubscribedTopicName.Values)
                    {
                        var topicTypeName = this.Topics[topicName].GetType().Name;
                        ConsoleWriteLineWithColor($"\t{topicName}({topicTypeName})", ConsoleColor.White); 
                    }
                    if (node.PublishedTopicName.Count != 0)
                    {
                        ConsoleWriteLineWithColor("Publish to topics: ", ConsoleColor.White);
                    }
                    else
                    {
                        ConsoleWriteLineWithColor("Published to: no topics: ", ConsoleColor.White);
                    }
                    foreach (var topicName in node.PublishedTopicName.Values)
                    {
                        var topicTypeName = this.Topics[topicName].GetType().Name;
                        ConsoleWriteLineWithColor($"\t{topicName}({topicTypeName})", ConsoleColor.White);
                    }
                }
                else
                {
                    throw new NodeNotExistExecption(nodeName);
                }
            }
            catch (NodeNotExistExecption)
            {
                LogError($"该名称的节点不存在{nodeName}", "Node Not Exist");
            }
            catch
            {
                LogError("Some error occurred when reflecting node", "Node info");
            }
        }
        private void NodeListHandler()
        {
            try
            {
                if(this.Nodes.Count == 0)
                {
                    ConsoleWriteLineWithColor("there is no nodes", ConsoleColor.White);
                    return;
                }
                foreach(var name in this.Nodes.Keys)
                {
                    var node = this.Nodes[name];
                    var typeName = node.GetType().FullName;
                    ConsoleWriteLineWithColor($"\tName:{name}, Type:{typeName}, IsRunning: {node.IsRunning} ", ConsoleColor.White);
                }
            }
            catch
            {
                LogError("Some error occurred when reflecting node", "Node list");
            }
        }
        private void NodeExecuteHandler(string cmd)
        {
            var nodeCmd = cmd.Split(" ", 2, SplitOption);
            var nodeName = nodeCmd[0];
            try
            {               
                if(this.Nodes.ContainsKey(nodeName))
                {
                    var node = this.Nodes[nodeName];
                    if(node is ICommandInteractive)
                    {
                        var exeNode = node as ICommandInteractive;
                        exeNode.ExecuteCommand(nodeCmd[1], false);
                    }
                    else
                    {
                        throw new NodeNotSupportCommandException();
                    }
                }
                else
                {
                    throw new NodeNotExistExecption();
                }
            }
            catch (IndexOutOfRangeException)
            {
                LogError("未传入命令", "Node execute");
            }
            catch (NodeNotSupportCommandException)
            {
                LogError("该节点不支持执行命令", "Node execute");
            }
            catch (NodeNotExistExecption)
            {
                LogError($"该名称的节点不存在{nodeName}", "Node Not Exist");
            }
            catch(Exception e)
            {
                LogError("节点内部错误", "Node execute");
                ConsoleWriteLineWithColor(e.StackTrace, ConsoleColor.White);
            }
        }
        private void TopicNewHandler(string args)
        {
            try
            {
                var topicNewArgs = args.Split(" ", 3, SplitOption);
                string topicTypeName = topicNewArgs[0];
                Type topicType = null;
                foreach(var asm in this.LoadedAsm)
                {
                    topicType = asm.assembly.GetType(asm.ns + "." + topicTypeName);
                    if(topicType!=null)
                    {
                        break;
                    }
                }
                if (topicType == null)
                {
                    throw new TopicTypeNotFoundException(topicTypeName);
                }
                var topicName = topicNewArgs[1];
                if(this.Topics.ContainsKey(topicName))
                {
                    throw new AlreadyExistException(topicName);
                }
                var topic = Activator.CreateInstance(topicType) as Topic;
                if(topic == null)
                {
                    throw new TopicInstanceCreateFailedExcepiton();
                }
                this.RegisterTopic(topicName, topic);
                LogInfo("成功添加话题", "Topic new");
            }
            catch(IndexOutOfRangeException)
            {
                LogError("topic new命令的参数不正确", "Invalid Command");
                ConsoleWriteLineWithColor("用法：topic new <话题类型名称> <话题名称>", ConsoleColor.Yellow);
            }
            catch(TopicTypeNotFoundException ttnfe)
            {
                LogError($"未在已加载的程序集中找到指定名称的话题类型（{ttnfe.TopicTypeName}）", "Topic Not Found");
            }
            catch(AlreadyExistException aee)
            {
                LogError($"话题的名称已经存在（{aee.ExistedName}）", "Name Already Exists");
            }
            catch(TopicInstanceCreateFailedExcepiton)
            {
                LogError($"话题构造失败，可能是话题没有实现无参数的构造函数或者没有实现Topic类的抽象方法", "Topic new");
            }
            catch(Exception e)
            {
                LogError("未预定义的异常", "Topic new");
                ConsoleWriteLineWithColor(e.StackTrace, ConsoleColor.Yellow);
            }
        }
        private void TopicPublishHandler(string args)
        {
            try
            {
                var topicPubArgs = args.Split(" ", 2, SplitOption);
                var topicName = topicPubArgs[0];
                if(this.Topics.ContainsKey(topicName))
                {
                    var topic = this.Topics[topicName];
                    Type msgType = topic.MessageType;
                    try
                    {
                        var msg = Activator.CreateInstance(msgType, new object[] { topicPubArgs[1] ,this}) as Message;
                        if (msg != null)
                        {
                            topic.AddRaw(msg);
                            LogInfo("Successfully published message", "Topic pub");
                        }
                        else
                        {
                            throw new MessageConstructFailedException();
                        }
                    }
                    catch (MessageConstructFailedException)
                    {
                        throw;
                    }
                    catch
                    {
                        throw new MessageConstructFailedException();
                    }

                }
                else
                {
                    throw new TopicNotExistException(topicName);
                }
            }
            catch(IndexOutOfRangeException)
            {
                LogError("参数数目不正确", "Topic pub");
                ConsoleWriteLineWithColor("用法：topic pub <话题名称> <消息的构造函数的参数>", ConsoleColor.Yellow);
            }
            catch(TopicNotExistException tnee)
            {
                LogError("该名称的话题不存在", "Topic pub");
            }
            catch(MessageConstructFailedException)
            {
                LogError("Message构造失败，可能是参数无法被构造函数解析","Message create failed");
            }
            catch(Exception e)
            {
                LogError("未预定义的异常", "Topic pub");
                ConsoleWriteLineWithColor(e.StackTrace, ConsoleColor.Yellow);
            }
        }
        private void TopicListHandler()
        {
            try
            {
                if(this.Topics.Count == 0)
                {
                    ConsoleWriteLineWithColor("there is no topic", ConsoleColor.White);
                }
                else
                {
                    foreach(var t in this.Topics)
                    {
                        var topicName = t.Key;
                        var topicTypeName = t.Value.GetType().Name;
                        var topicMsgTypeName = t.Value.MessageType.Name;
                        ConsoleWriteLineWithColor($"\ttopic name: {topicName}, topic type: {topicTypeName}, message type: {topicMsgTypeName}",ConsoleColor.White);
                    }
                }
            }
            catch(Exception e)
            {
                LogError("Some error occurred when reflecting topic", "Topic list");
            }
        }
        private void TopicEchoHandler(string args)
        {
            try
            {
                var topicName = args.Trim();
                if (!this.Topics.ContainsKey(topicName))
                {
                    throw new TopicNotExistException(topicName);
                }
                var topic = this.Topics[topicName];
                MessageCallback<Message> listener = (Message msg) => { ConsoleWriteLineWithColor(msg.ToString()+"\n",ConsoleColor.White); };
                ConsoleWriteLineWithColor("开始侦听，按q退出", ConsoleColor.Yellow);
                topic.MessageAddedRaw += listener;
                while(true)
                {
                    var key = Console.ReadKey(true);
                    if(key.Key == ConsoleKey.Q)
                    {
                        break;
                    }
                }
                topic.MessageAddedRaw -= listener;
            }
            catch
            {

            }
        
        }

    }

}
